/*
  Copyright (C) 2011 Pavel Lajsner <Pavel.Lajsner(at)gmail.com>.

  This file is replacement application of Ikea cooker.

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation, 
  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

/*

  $File Name: main.c$
  $Version: 1.0.29.0$
  $Date: May-5-2009$ 
  $Last Modified By: r30323$

  Changelog:
   
*/

//#define DEBUG

#define BDM
#define UNPROT


#include <MC9S08QD4.h>

#define ICSC2_INIT  0x80    // for 2MHz bus clock @ QD4

#define _Stop asm ( stop; )
  /*!< Macro to enter stop modes, STOPE bit in SOPT1 register must be set prior to executing this macro */

#define _Wait asm ( wait; )
  /*!< Macro to enter wait mode */

/* NVPROT - macro for reading non volatile register        Nonvolatile FLASH Protection Register; 0x0000FFBD */
/* Tip for register initialization in the user code:   */
const char NVPROT_INIT @0xFFBD = 0x00;      // all protected
/* NVOPT - macro for reading non volatile register         Nonvolatile Flash Options Register; 0x0000FFBF */
/* Tip for register initialization in the user code: */ 
#ifndef UNPROT
const char NVOPT_INIT @0x0000FFBF = 0b01000000; // secured, key disabled
#else
#warning "UNPROT option set = UNSECURED!"
const char NVOPT_INIT @0x0000FFBF = 0b01000010; // unsecured, key disabled
#endif


#define BUSCLK 2000000.0

#define SW1     PTAD_PTAD2
#define SW1_DDR PTADD_PTADD2
#define SW1_PUE PTAPE_PTAPE2
#define SW1_KBI KBIPE_KBIPE2

#define SW2     PTAD_PTAD3
#define SW2_DDR PTADD_PTADD3
#define SW2_PUE PTAPE_PTAPE3
#define SW2_KBI KBIPE_KBIPE3

#define HEATER1     PTAD_PTAD0
#define HEATER1_DDR PTADD_PTADD0

#define HEATER2     PTAD_PTAD1
#define HEATER2_DDR PTADD_PTADD1


#define TPM1DIV 0b111   // :128 = 15.6kHz tick for 2MHz BUS
#define TPM1US(x) (word)(((x)/1000000.0) * (BUSCLK/(1<<TPM1DIV)))  // in us

#define TPM2DIV 0b011
#define TPM2US(x) (word)(((x)/1000000.0) * (BUSCLK/(1<<TPM2DIV)))  // in us



#define TIMEOUT 45   // in 4s increments        (45 = 3 min)

#define DEBOUNCE 200
#define STEPS    80
#define HEATHI   (STEPS+1)
#define HEATLO   (HEATHI/3)
#define HEATXX   1


#pragma mark -
#pragma mark >>> Variables
/*****************************************************************************
*
* variables definition
*
******************************************************************************/

const heattab[]={0, HEATHI, HEATLO, HEATXX};

#pragma DATA_SEG SHORT _DATA_ZEROPAGE

byte heat1, heat2;
byte sw1_cnt, sw2_cnt;
byte sw1, sw2;
byte sw1_arm, sw2_arm;
byte cnt;
byte nosleep;
word timeout;


#pragma DATA_SEG DEFAULT


void interrupt VectorNumber_Vkeyboard1 KBI_Int(void) 
{
  KBISC_KBACK  = 1;      
  KBISC_KBIE = 0;      
}

#pragma mark -
/*****************************************************************************
*
* main
*
******************************************************************************/

void main(void)
{

#ifdef BDM
#warning "BDM option set!"
#endif

#if defined(DEBUG) || defined (BDM) 
  SOPT1 = SOPT1_STOPE_MASK | SOPT1_BKGDPE_MASK | SOPT1_COPE_MASK | SOPT1_COPT_MASK;  // BDM pin only for debug
#else
  SOPT1 = SOPT1_STOPE_MASK;  // no BDM pins in run mode
#endif

  SPMSC1_LVDSE = 0; // LVD off in STOP mode
  
  ICSC2 = ICSC2_INIT;   //2MHz
  ICSTRM = *(char *)(0xFFAF); // trim int. oscillator, keep 2MHz BUS

  SW1_PUE = 1;
  SW2_PUE = 1;

  HEATER1 = 0;     //LOW
  HEATER1_DDR = 1; //OUT

  HEATER2 = 0;     //LOW
  HEATER2_DDR = 1; //OUT

  SW1_KBI = 1;
  SW2_KBI = 1;

  sw1_cnt = 0;
  sw2_cnt = 0;
  
  heat1 = 0;
  heat2 = 0;

  timeout = 0;
  nosleep = 0;

  TPMSC = 0b00001000 | TPM1DIV;    // 15625Hz tick, divider 128
  TPMC0SC = 0b00010000;  // software output compare

  for (;;)
  {
    __RESET_WATCHDOG();   /* feeds the dog */

    cnt++;
    if (cnt > STEPS)
      cnt = 0;
    
    HEATER1 = ((heattab[heat1] > cnt)? 1 : 0);
    HEATER2 = ((heattab[heat2] > cnt)? 1 : 0);

    sw1 = SW1;
    sw2 = SW2;

    if (0 == sw1)
    {
      timeout = TIMEOUT;

      if (sw1_cnt) 
      {
        sw1_cnt--;
       
        if ((0 == sw1_cnt) && (1 == sw1_arm))
        {
          sw1_arm = 0;
          heat1++;
          if (heat1 > 2)
            heat1 = 0;
        }
      }
    } 
    else 
    {
      if (sw1_cnt < DEBOUNCE)
        sw1_cnt++;
        if (sw1_cnt == DEBOUNCE)
          sw1_arm = 1;
    }
    
    if (0 == sw2)
    {
      timeout = TIMEOUT;

      if (sw2_cnt) 
      {
        sw2_cnt--;
       
        if ((0 == sw2_cnt) && (1 == sw2_arm))
        {
          sw2_arm = 0;
          heat2++;
          if (heat2 > 2)
            heat2 = 0;
        }    
      }
    }
    else 
    {
      if (sw2_cnt < DEBOUNCE)
        sw2_cnt++;
        if (sw2_cnt == DEBOUNCE)
          sw2_arm = 1;
    }

    if ((0 == heat1) && (0 == heat2) && timeout)
      timeout = 1;

    if (TPMSC_TOF) 
    {
      TPMSC_TOF = 0;
      if (timeout)
        timeout--;
    }
    
    if (1 == timeout) 
    {
      if (heat1) heat1 = 3;
      if (heat2) heat2 = 3;
    }

    if (0 == timeout)
    {

      timeout = 0;

      sw1_arm = 1;
      sw2_arm = 1;
      
      heat1 = 0;
      heat2 = 0;
      HEATER1 = 0;
      HEATER2 = 0;

      // enter STOP3 mode
      KBISC_KBACK  = 1;      
      KBISC_KBIE = 1;      
      asm CLI;             // enable ints
      asm STOP;            // go to STOP mode
      asm SEI;             // disable ints
      
    }
  }
}

#pragma NO_EXIT
void unused(void)
{
  asm dcb 0x8D;
}
